import G6, {Graph, IGroup, IShape, ModelConfig} from '@antv/g6';
import {Item} from '@antv/g6-core/lib/types';
import NodeStateType from '../consts/node-state-type';
import NodeAttrField from '../consts/node-attr-field';
import {IElement} from '@antv/g-base/src/interfaces';
import anchorStyle from '../def/anchor-style';
import {ShapeAttrs} from '@antv/g-base/src/types';
import StateType from '../consts/state-type';

const userTaskDefaultOptions = {
    icon: null,
    iconStyle: {
        width: 12,
        height: 12,
        left: 2,
        top: 2,
    },
    style: {
        shadowOffsetX: 0,
        shadowOffsetY: 4,
        shadowBlur: 10,
        shadowColor: 'rgba(13, 26, 38, 0.08)',
        lineWidth: 1,
        radius: 4,
        strokeOpacity: .7,
        fill: '#e1f5fe',
        stroke: '#29b6f6',
        cursor: 'default',
    },
    textStyle: {
        textAlign: 'center',
        textBaseline: 'middle',
        fill: '#999999',
        cursor: 'move',
    },
    stateStyles: {
        selected: {
            fill: '#95D6FB',
        },
        hover: {
            cursor: 'move',
        }
    },
    anchorStyle: {
        normalStyle: {
            ...anchorStyle.normalStyle,
            fill: '#fff',
            stroke: '#64b5f6',
        },
        hideStyle: {
            ...anchorStyle.hideStyle,
            fill: '#fff',
        },
        showStyle: {
            ...anchorStyle.showStyle,
            fill: '#fff',
        },
        focusStyle: {
            ...anchorStyle.focusStyle,
            fill: '#d0f2ff',
        },
        nearStyle: {
            ...anchorStyle.nearStyle,
            fill: '#81d4fa',
        },
        boldStyle: {
            ...anchorStyle.boldStyle,
            fill: '#e1f5fe',
            stroke: '#81d4fa',
        },
        thinStyle: {
            ...anchorStyle.thinStyle,
            fill: '#fff',
            stroke: '#64b5f6',
        }
    },
    selectboxStyle: {
        radius: 0,
        stroke: '#aaaaaa',
        lineWidth: 1,
        lineDash:  [2, 2],
    }
};

export default function () {

    G6.registerNode('user-task', {
        shapeType: 'rect',
        labelPosition: 'bottom',
        options: {
            ...userTaskDefaultOptions
        },
        getShapeStyle(cfg: ModelConfig) {
            cfg.size = [100, 50];
            // const width = cfg.size[0];
            // const height = cfg.size[1];
            const [width, height] = cfg.size;
            const style = {
                x: 0 - width / 2,
                y: 0 - height / 2,
                width,
                height,
                ...userTaskDefaultOptions.style,
            };
        },
        /**
         * 绘制节点，包含文本
         * @param  {Object} cfg 节点的配置项
         * @param  {G.Group} group 图形分组，节点中的图形对象的容器
         * @return {G.Shape} 绘制的图形，通过 node.get('keyShape') 可以获取到
         */
        draw(cfg: ModelConfig | undefined, group: IGroup | undefined): IShape {
            const shape = group?.addShape('rect', {
                draggable: false,
                attrs: {
                    ...userTaskDefaultOptions.style,
                    x: -50,
                    y: -25,
                    width: 100,
                    height: 50,
                    // lineWidth: 1,
                    // cursor: 'move',
                    lineDash: /^ghost/.test(cfg?.id as string) ? [5, 5] : [0, 0],
                    opacity: /^ghost/.test(cfg?.id as string) ? 0.5 : 1,
                    '$isMain': true,
                }
            });

            if (cfg?.label && cfg.label) {
                // 如果有文本
                // 如果需要复杂的文本配置项，可以通过 labeCfg 传入
                // const style = (cfg.labelCfg && cfg.labelCfg.style) || {};
                // style.text = cfg.label;
                group?.addShape('text', {
                    // attrs: style
                    attrs: {
                        ...(userTaskDefaultOptions.textStyle as ShapeAttrs),
                        x: 0, // 居中
                        y: 0,
                        text: cfg.label,
                        opacity: /^ghost/.test(cfg?.id as string) ? 0.5 : 1
                    },
                    // must be assigned in G6 3.3 and later versions. it can be any value you want
                    name: 'text-shape',
                    // 设置 draggable 以允许响应鼠标的图拽事件
                    draggable: true,
                });
            }

            // shape?.toFront();
            return shape as IShape;
        },
        /**
         * 绘制后的附加操作，默认没有任何操作
         * @param  {Object} cfg 节点的配置项
         * @param  {G.Group} group 图形分组，节点中的图形对象的容器
         */
        afterDraw(cfg: ModelConfig | undefined, group: IGroup | undefined) {

            const bbox = group?.get('children')[0].getBBox();
            const {width, height, minX, minY} = bbox;
            group?.addShape('image', {
                attrs: {
                    x: 4 - width / 2,
                    y: 4 - height / 2,
                    img: require('@/assets/icons/flow/icon_user.svg').default,
                    width: 16,
                    height: 16,
                    cursor: 'move'
                },
                draggable: true,
                // must be assigned in G6 3.3 and later versions. it can be any value you want
                name: 'image-shape',
            });

            // @ts-ignore
            this.drawAnchor(group);
        },
        getAnchorPoints() {
            return [
                [0.5, 0], // top
                [1, 0.5], // right
                [0.5, 1], // bottom
                [0, 0.5], // left
            ];
        },
        drawAnchor(group: IGroup | undefined) {
            // @ts-ignore
            // const group = node.getContainer();
            const bbox = group?.get('children')[0].getBBox();
            // @ts-ignore
            const {width, height, minX, minY} = bbox;
            // @ts-ignore
            const anchorPoints = this.getAnchorPoints();
            anchorPoints.forEach((p: number[], index: number) => {
                const anchor = group?.addShape('marker', {
                    attrs: {
                        ...userTaskDefaultOptions.anchorStyle.normalStyle,
                        x: minX + width * p[0],
                        y: minY + height * p[1],
                        r: 4,
                        // fill: '#fff',
                        // stroke: '#64b5f6',
                        cursor: 'crosshair',
                        opacity: 0,
                        '$isAnchor': true,
                        '$anchorIndex': index
                    },
                    draggable: true,
                    capture: true
                });

                if (anchor) {
                    anchor.toFront();
                }
            });
        },
        /**
         * 设置节点的状态，主要是交互状态，业务状态请在 draw 方法中实现
         * 单图形的节点仅考虑 selected、active 状态，有其他状态需求的用户自己复写这个方法
         * @param  {String} name 状态名称
         * @param  {Object} value 状态值
         * @param  {Node} node 节点
         */
        setState(name: string | undefined, value: string | boolean | undefined, node: Item | undefined) {
            if (!node) {
                return ;
            }
            if (name === StateType.SELECTED) {
                const group = node?.getContainer();

                const existSelectBox = group?.find((item: IShape) => item.attr(NodeAttrField.SELECTBOX_IS_SELECTBOX)) as IElement;
                if (value) {
                    if (existSelectBox) {
                        return ;
                    }
                    const shape = group?.addShape('rect', {
                        draggable: false,
                        attrs: {
                            ...userTaskDefaultOptions.selectboxStyle,
                            x: -(node.getBBox().width - 1 + 10) / 2,
                            y: -(node.getBBox().height - 1 + 10) / 2,
                            width: node.getBBox().width - 1 + 10,
                            height: node.getBBox().height - 1 + 10,
                            '$isSelectBox': true
                        }
                    });
                } else {
                    group?.removeChild(existSelectBox);
                }
            } else if (name === NodeStateType.NODE_ANCHOR_VISIBLE) {
                if (value) {
                    const group = node?.getContainer();
                    const anchorElements = group?.getChildren().filter(item => item.attr(NodeAttrField.ANCHOR_IS_ANCHOR));
                    anchorElements?.forEach(item => {
                        item.attr(userTaskDefaultOptions.anchorStyle.showStyle);
                    });
                } else {
                    const group = node?.getContainer();
                    const anchorElements = group?.getChildren().filter(item => item.attr(NodeAttrField.ANCHOR_IS_ANCHOR));
                    anchorElements?.forEach(item => {
                        item.attr(userTaskDefaultOptions.anchorStyle.hideStyle);
                    });
                }
            } else if (name === NodeStateType.NODE_ANCHOR_BOLD) {
                if (value) {
                    node?.getContainer().getChildren()
                        .filter(item => item.attr(NodeAttrField.ANCHOR_IS_ANCHOR))
                        .forEach(item => item.attr(userTaskDefaultOptions.anchorStyle.boldStyle));
                } else {
                    node?.getContainer().getChildren()
                        .filter(item => item.attr(NodeAttrField.ANCHOR_IS_ANCHOR))
                        .forEach(item => item.attr(userTaskDefaultOptions.anchorStyle.thinStyle));
                }
            } else if (name === NodeStateType.NODE_ANCHOR_FOCUS) {
                const group = node?.getContainer();
                const anchorElements = group?.getChildren().filter(item => item.attr(NodeAttrField.ANCHOR_IS_ANCHOR));
                anchorElements?.forEach(item => item.attr(userTaskDefaultOptions.anchorStyle.showStyle));
                const targetAnchorElement = anchorElements?.find(item => item.attr(NodeAttrField.ANCHOR_ANCHOR_INDEX) === value);
                targetAnchorElement?.attr(userTaskDefaultOptions.anchorStyle.focusStyle);
            } else if (name === NodeStateType.NODE_ANCHOR_NEAR) {
                const group = node?.getContainer();
                const anchorElements = group?.getChildren().filter(item => item.attr(NodeAttrField.ANCHOR_IS_ANCHOR));
                anchorElements?.forEach(item => item.attr(userTaskDefaultOptions.anchorStyle.boldStyle));
                const targetAnchorElement = anchorElements?.find(item => item.attr(NodeAttrField.ANCHOR_ANCHOR_INDEX) === value);
                targetAnchorElement?.attr(userTaskDefaultOptions.anchorStyle.nearStyle);
            }
        },
    });
}
